<template>
  <div>

    <div style="position: absolute;top: 5px; left: 40%;color: red;font-size: 12px;">
      * 大模型节点用户提示词为LLM的输入，可以使用 "{ {入参} }"来动态获取参数 *
    </div>
    <div style="position: absolute;top: 50px;right: 50px;z-index: 100">
      <el-button type="warning" size="small" @click="tinyflowTest()">测试</el-button>
      <el-button type="primary" size="small" @click="saveTinyFlow()" v-show="canSaveFlag">保存</el-button>
    </div>

    <div style="width: 100%; height: calc(100vh - 16px)">
      <Tinyflow
          ref="tinyFlowRef"
          :className="'custom-class'"
          :style="{ width: '100%', height: '100%' }"
          :data="initialData"
          :provider="provider"
          :on-node-execute="onNodeExecute"
      />
    </div>

    <el-drawer title="流程测试" v-model="tinyFlowTestOpen" size="40%" append-to-body destroy-on-close>
      <el-form ref="tinyFlowTestFormDataRef" :model="tinyFlowTestData" :rules="tinyFlowTestFormRules" label-width="80px" lab>
        <el-form-item v-for="item in tinyFlowTestFormData" :key="item.label" :label="item.label" :prop="item.label">
          <!--   附件 -->
          <file-upload v-if="item.type === 'File'" v-model="tinyFlowTestData[item.label]" limit="1"
                       :fileType="['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf']"/>
          <!--   Boolean  -->
          <el-select v-if="item.type === 'Boolean'" v-model="tinyFlowTestData[item.label]" placeholder="请选择">
            <el-option value="">请选择</el-option>
            <el-option key="true" label="true" value="true"></el-option>
            <el-option key="false" label="false" value="false"></el-option>
          </el-select>
          <!--   数字 -->
          <el-input-number v-if="item.type === 'Number'" v-model="tinyFlowTestData[item.label]" placeholder="请输入" style="width: 100%"/>
          <!--  其他 -->
          <el-input v-if="item.type !== 'File' && item.type !== 'Boolean' && item.type !== 'Number'" v-model="tinyFlowTestData[item.label]"
                    placeholder="请输入"/>
        </el-form-item>
        <div class="dialog-footer" style="text-align: right">
          <el-button type="primary" @click="testSubmitFormStore" :loading="loading">执 行</el-button>
        </div>
        <el-divider content-position="left">测试结果</el-divider>
        <div style="padding: 5px 15px; height: 250px;overflow: auto;" v-if="tinyFlowTestResult">
          <JsonViewer :value="tinyFlowTestResult" :expanded="true"/>
        </div>
        <div style="padding: 5px 15px; height: 250px;width: 100%" v-else>
          <el-empty description="暂未执行完成，请稍候..."/>
        </div>

        <el-divider content-position="left">执行步骤</el-divider>

        <div class="demo-collapse" v-if="workFlowExeDataArr.length > 0" style="padding: 5px 15px">
          <el-collapse expand-icon-position="right">
            <el-collapse-item v-for="item in workFlowExeDataArr" :title="item.nodeName" :name="item.nodeId">
              <template #icon="{ isActive }">
                <span style=" margin: 0 8px 0 auto;">
                  <el-icon color="green">
                    <CircleCheck/>
                  </el-icon>
                </span>
              </template>
              <JsonViewer :value="item.result" :expanded="true"/>
            </el-collapse-item>
          </el-collapse>
        </div>
        <div v-else>
          <el-empty description="暂未点击执行，请稍候..."/>
        </div>

      </el-form>
    </el-drawer>
  </div>

</template>

<script setup>

import {Tinyflow} from '@tinyflow-ai/vue';
import "@tinyflow-ai/ui/dist/index.css";
import {canSaveFlag, designAiWorkflow, excWorkflow, flowEdges, flowNodes, knowledgeList, llmModelList} from "@/api/ai/aiFlow.js";
import useUserStore from "@/store/modules/user.js";
import {JsonViewer} from "vue3-json-viewer"
import "vue3-json-viewer/dist/vue3-json-viewer.css";
import {CircleCheck} from "@element-plus/icons-vue";
import {initSSEInstance} from "@/api/common.js";

const {proxy} = getCurrentInstance();
const tinyFlowRef = ref(null);
const tinyFlowTestOpen = ref(false)
const tinyFlowTestData = ref({})
const tinyFlowTestFormData = ref([])
const tinyFlowTestFormRules = ref({})
const tinyFlowTestFormDataRef = ref(null)
const tinyFlowTestResult = ref(null)
const loading = ref(false);
let eventSourceInstance = null

// sse连接相关信息
const userStore = useUserStore()
let isProcessing = false;
const messageQueue = [];
const workFlowExeDataArr = ref([])

const props = defineProps({
  flowItem: {
    type: Object,
    required: true
  }
})

const provider = {
  llm: () => llmModelList.value,
  knowledge: () => knowledgeList.value,
}

const initialData = ref({
  nodes: flowNodes.value,
  edges: flowEdges.value,
});

function onNodeExecute(currentNode) {
  console.log(currentNode)
  proxy.$modal.msgSuccess("节点执行,暂不支持单节点运行测试");
}

function tinyflowTest() {
  // 获取开始节点参数
  getStartNodeParam()
  // 打开测试窗口
  tinyFlowTestOpen.value = true
}

function saveTinyFlow() {
  console.log(props.flowItem)
  const graph = JSON.stringify(tinyFlowRef.value.getData())
  designAiWorkflow(props.flowItem.id, graph).then(resp => {
    proxy.$modal.msgSuccess("保存成功");
  })
}

function validateStartEndNode() {
  const nodes = tinyFlowRef.value.getData().nodes
  if (nodes.length === 0) {
    proxy.$modal.msgError("未添加节点");
    return
  }
  const startNode = nodes.find(node => node.type === 'startNode');
  const endNode = nodes.find(node => node.type === 'endNode');
  console.log(endNode)
  if (startNode === undefined || startNode === null) {
    proxy.$modal.msgError("请添加开始节点");
    return;
  }
  if (startNode.data.parameters === undefined || startNode.data.parameters.length === 0) {
    proxy.$modal.msgError("请添加开始节点的参数");
    return;
  }
  if (endNode === undefined || endNode === null) {
    proxy.$modal.msgError("请添加结束节点");
    return;
  }
  if (endNode.data.outputDefs === undefined || endNode.data.outputDefs.length === 0) {
    proxy.$modal.msgError("请添加结束节点的输出参数");
  }
}

function getStartNodeParam() {
  // 节点校验
  validateStartEndNode()
  const nodes = tinyFlowRef.value.getData().nodes
  const startNode = nodes.find(node => node.type === 'startNode');
  tinyFlowTestFormData.value = []
  tinyFlowTestFormRules.value = {}
  startNode.data.parameters.forEach((parameter) => {
    if (parameter.required === true) {
      tinyFlowTestFormRules.value[parameter.name] = [
        {required: true, message: '请输入' + parameter.name, trigger: parameter.dataType === 'Boolean' ? 'change' : 'blur'}
      ]
    }
    tinyFlowTestFormData.value.push({
      label: parameter.name,
      type: parameter.dataType
    })
  })
}

function testSubmitFormStore() {
  // 创建sse连接
  // 发送消息前，创建sse连接，保证发送前 sse连接已经建立
  if (eventSourceInstance === null || eventSourceInstance.readyState === EventSource.CLOSED) {
    // 未连接或离线的时候 进行sse连接
    eventSourceInstance = initSSEInstance('workflow', 'admin', userStore.name)
  }
  proxy.$refs["tinyFlowTestFormDataRef"].validate((valid) => {
    if (valid) {
      tinyFlowTestResult.value = null
      workFlowExeDataArr.value = []
      loading.value = true
      const graph = JSON.stringify(tinyFlowRef.value.getData())
      // 发送执行指令请求
      excWorkflow(graph, tinyFlowTestData.value, 'admin')
          .then(resp => {
            proxy.$modal.msgSuccess("测试执行成功");
          })
          .finally(() => {
            loading.value = false
          })
      // 消息监听
      // 消息监听接收消息
      eventSourceInstance.onmessage = function (event) {
        console.log('workflow-收到消息：' + event.data);
        messageQueue.push(event.data); // 将消息加入队列
        // 消息处理
        dealWithSSEMessage()
      }
      // 链接监听，异常监听
      eventSourceInstance.onerror = (error) => {
        console.error('flow-SSE与服务端连接发生错误', err);
        if (eventSourceInstance === null || eventSourceInstance.readyState === EventSource.CLOSED) {
          eventSourceInstance = initSSEInstance('workflow', 'admin', userStore.name)
        }
      }
    }
  })
}

function dealWithSSEMessage() {
  if (isProcessing || messageQueue.length === 0) {
    return
  }
  isProcessing = true;
  const data = messageQueue.shift();
  // 模拟异步处理（如需要等待前一条的结果）
  handleMessage(data);
  isProcessing = false;
  dealWithSSEMessage(); // 处理下一条
}

function handleMessage(flowNodeExcData) {
  // 将flowNodeExcData 转成json对象保存起来
  const flowNodeExcDataObj = JSON.parse(flowNodeExcData)
  workFlowExeDataArr.value.push(flowNodeExcDataObj)
  if (flowNodeExcDataObj.nodeType === 'endNode') {
    tinyFlowTestResult.value = flowNodeExcDataObj.result
  }
}
</script>
